#include "trackball.h"

glm::mat4 Trackball::GetViewMatrix(bool debug) const {
    if (!dragging)
        return view;
    
    // If start = end, the in-progress rotation we apply
    // will be the additive identity (0 matrix), which will
    // not jive well with the view.
    if (dragStart[0] == dragStop[0] &&
        dragStart[1] == dragStop[1]) {
        
        return view;
    }
    
    float dot   = glm::dot(dragStart, dragStop);
    float angle = TRACKBALL_SENSITIVITY * glm::acos(dot);
    
    glm::vec3 normal = glm::cross(dragStart, dragStop);
    glm::mat4 rot    = glm::rotate(view, angle, normal);
    
    if (debug) {
        printf("DragStart: "); PRINTV(dragStart);
        printf("DragStop:  "); PRINTV(dragStop);
        printf("Dot:       %f\n", dot);
        printf("Angle:     %f\n", angle);
        printf("Normal:    "); PRINTV(normal);
        printf("Current Matrix:\n"); PRINTM(view);
        printf("Dragged Matrix:\n"); PRINTM(rot);
    }
    
    return rot;
}

glm::vec3 Trackball::ToTrackballCoords(int i, int j) {
    float x =  2.0f * i / (float)resW - 1.0f,
          y = -2.0f * j / (float)resH + 1.0f;
    
    //*
    float d = rSq - x*x - y*y;
    
    if (d >= 0.0f) {
        return glm::vec3(x, y, glm::sqrt(d));
    } else {
        float r = glm::sqrt(x*x + y*y);
        return glm::vec3(x/r, y/r, 0.0f);
    }
    //*/
    
    /*
    float squareLength = x*x + y*y;
    float z
        = squareLength <= 0.5f * rSq
        ? glm::sqrt(rSq - squareLength)
        : rSq / glm::sqrt(squareLength);
    
    return glm::vec3(x,y,z);
    //*/
}

void Trackball::MouseUpdate(bool mouseDown, int i, int j) {
    if (dragging) {
        dragStop = ToTrackballCoords(i, j);
        
        if (!mouseDown) {
            // Stop dragging
            
            /*
            printf(
                "Stop  (%i,%i)/(%i,%i) => (%f,%f,%f)\n",
                i, j, resW, resH,
                dragStop[0], dragStop[1], dragStop[2]
            );
            */
            
            // Save the transformed view matrix as the current view
            view = GetViewMatrix(false);
            dragging = false;
        }
    } else {
        if (mouseDown) {
            // Start dragging
            dragStart = ToTrackballCoords(i, j);
            dragStop  = dragStart;
            
            /*
            printf(
                "Start (%i,%i)/(%i,%i) => (%f,%f,%f)\n",
                i, j, resW, resH,
                dragStop[0], dragStop[1], dragStop[2]
            );
            */
            
            dragging = true;
        }
    }
}